#include <assert.h>
#include <ratio>
#include <type_traits>
#include <iostream>

#define DebugNewTableSize std::ratio_multiply<std::ratio<1600>, std::ratio<1024>>::num
#define DebugNewHash(p) std::hash<void*>{}(p) % DebugNewTableSize

struct NewPtrNode
{
	NewPtrNode* next = NULL;
	const char* fileName = NULL;
	const char* funcName = NULL;
	size_t line = 0;
	size_t size = 0;
};

static NewPtrNode* newPtrList[DebugNewTableSize] = {};

void* operator new(size_t size, const char* file, const char* func, size_t line)
{
	size_t s = size + sizeof(NewPtrNode);
	NewPtrNode* p = (NewPtrNode*)malloc(s);
	assert(p);

	void* rtP = (char*)p + sizeof(NewPtrNode);
	size_t hashId = DebugNewHash(rtP);
	//lock
	p->next = newPtrList[hashId];
	p->fileName = file;
	p->funcName = func;
	p->line = line;
	p->size = size;
	newPtrList[hashId] = p;
	//unlock

	std::cout << file << "," << func << "," << line << std::endl;
	return rtP;
}

void* operator new[](size_t size, const char* file, const char* func, size_t line)
{
	return operator new(size, file, func, line);
}

void operator delete(void* ptr)
{
	if (!ptr)
		return;

	size_t hashId = DebugNewHash(ptr);

	//lock
	NewPtrNode* ptrNode = newPtrList[hashId];
	while (ptrNode)
	{
		if ((char*)ptrNode + sizeof(NewPtrNode) != ptr)
		{
			ptrNode = ptrNode->next;
			continue;
		}

		free(ptrNode);
		//unlock
		return;
	}
	//unlock

	free(ptr);
}

class A
{
public:
	A() { std::cout << "A" << std::endl; }
	~A() { std::cout << "~A" << std::endl; }

private:

};

using namespace std;

int main()
{
	int *p1 = new(__FILE__, __FUNCSIG__, __LINE__) int;
	delete p1;

	A* p2 = new(__FILE__, __FUNCSIG__, __LINE__) A;
	delete p2;

	return 0;
}